package com.fingard.dsp.bank.directbank.weixin01;

import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.bankInterface.IEntrustRec;
import com.fingard.dsp.bank.reqrespobj.entrust.ReqEntrustRec;
import com.fingard.dsp.bank.reqrespobj.entrust.ReqQueryEntrustRec;
import com.fingard.dsp.bank.reqrespobj.entrust.RetAtsEntrustRec;
import com.fingard.dsp.bank.reqrespobj.entrust.RetAtsQueryEntrustRec;
import com.fingard.text.StringHelper;
import com.fingard.text.XmlHelper;
import com.fingard.xml.XmlTextReader;

import java.util.ArrayList;

/**
 * 微信委托代扣扣款
 */
public class WEIXIN01EntrustRec extends WEIXIN01Base implements IEntrustRec {
    /**
     * 参考文档：https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_3&index=8
     *
     * 业务场景：委托代扣可应用于定期扣款或需事后扣款以期提高效率的场景。例如但不限于，会员制缴费、水电煤缴费、黄钻绿钻增值服务、打车类软件、停车场或高速公路无人缴费、理财通基金定投、信用卡还款等通过用户授权给商户，进行委托扣款的场景。
     * 注：扣费请求首先按签约协议中记录的优先支付方式扣费，否则依次按以下顺序扣费：零钱、信用卡、借记卡
     * 注意：对于自动续费的代扣申请，微信将延迟24小时进行扣款（首次签约可在签约后12小时内立即扣款成功，不受此规则限制）
     *
     * 请求Url https://api.mch.weixin.qq.com/pay/pappayapply
     * 是否需要证书 否
     * 请求方式 post
     * 返回参数说明 扣款接口请求成功，返回success仅代表扣款申请受理成功，不代表扣款成功。扣款是否成功以支付通知的结果为准。
     *
     * @param p_req
     * @return
     */
    @Override
    public RetAtsEntrustRec submitEntrustRec(ReqEntrustRec p_req) {
        RetAtsEntrustRec retAts = new RetAtsEntrustRec(p_req);

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_req.ownAct,"unifiedorder");
            if (actItem != null) {
                ArrayList<String> arrayParams = new ArrayList<String>();

                StringBuilder sbXml = new StringBuilder();
                sbXml.append("<xml>\r\n");

                sbXml.append("  <appid>" + actItem.appId + "</appid>\r\n");
                arrayParams.add("appid=" + actItem.appId);

                sbXml.append("  <mch_id>" + actItem.merchantId + "</mch_id>\r\n");
                arrayParams.add("mch_id=" + actItem.merchantId);

                String nonceStr = get_nonce_str();
                sbXml.append("  <nonce_str>" + nonceStr + "</nonce_str>\r\n");
                arrayParams.add("nonce_str=" + nonceStr);

                if (StringHelper.hasAnyChar(p_req.description)) {
                    String body = XmlHelper.encode(p_req.description);
                    sbXml.append("  <body>" + body + "</body>\r\n");
                    arrayParams.add("body=" + body);
                }

                if (StringHelper.hasAnyChar(p_req.attach)) {
                    sbXml.append("  <attach>" + p_req.attach + "</attach>\r\n");
                    arrayParams.add("attach=" + p_req.attach);
                }

                sbXml.append("  <out_trade_no>" + p_req.rdSeq + "</out_trade_no>\r\n");
                arrayParams.add("out_trade_no=" + p_req.rdSeq);

                if (StringHelper.hasAnyChar(p_req.amount)) {
                    String total_fee = StringHelper.amountMultiply100(p_req.amount);
                    sbXml.append("  <total_fee>" + total_fee + "</total_fee>\r\n");
                    arrayParams.add("total_fee=" + total_fee);
                }

                if (StringHelper.hasAnyChar(p_req.cur)) {
                    sbXml.append("  <fee_type>" + p_req.cur + "</fee_type>\r\n");
                    arrayParams.add("fee_type=" + p_req.cur);
                }

                if (StringHelper.hasAnyChar(p_req.createIP)) {
                    sbXml.append("  <spbill_create_ip>" + p_req.createIP + "</spbill_create_ip>\r\n");
                    arrayParams.add("spbill_create_ip=" + p_req.createIP);
                }

                String notifyUrl = actItem.notifyURLMap.get("entrustRec");
                if (StringHelper.hasAnyChar(notifyUrl)) {
                    sbXml.append("  <notify_url>" + notifyUrl + "</notify_url>\r\n");
                    arrayParams.add("notify_url=" + notifyUrl);
                }

                sbXml.append("  <trade_type>PAP</trade_type>\r\n");
                arrayParams.add("trade_type=PAP");

                if (StringHelper.hasAnyChar(p_req.channelAuthCode)) {
                    String channelAuthCode = XmlHelper.encode(p_req.channelAuthCode);
                    sbXml.append("  <contract_id>" + channelAuthCode + "</contract_id>\r\n");
                    arrayParams.add("contract_id=" + channelAuthCode);
                }

                String[] signParams = new String[arrayParams.size()];
                arrayParams.toArray(signParams);
                String sign = signMessage(signParams, actItem.saltKey);
                sbXml.append("  <sign>" + sign + "</sign>\r\n");
                sbXml.append("</xml>");

                String[] tmpStrRet = sendToBank(sbXml.toString(), "pappayapply");

                if (tmpStrRet[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1],	tmpSbMsg);
                    if (tmpBkReader != null) {
                        String return_code = tmpBkReader.getFirstText("/xml/return_code");
                        String return_msg = tmpBkReader.getFirstText("/xml/return_msg");
                        String result_code = tmpBkReader.getFirstText("/xml/result_code");
                        String err_code = tmpBkReader.getFirstText("/xml/err_code");
                        String trade_state = tmpBkReader.getFirstText("/xml/trade_state");
                        if (return_code != null && "SUCCESS".equals(return_code)) {
                            retAts.respCode = "0";
                            retAts.respInfo = tmpBkReader.getFirstText("/xml/return_msg");
                            if ("SUCCESS".equals(result_code)) {
                                retAts.transState = "0";
                            } else if ("FAIL".equals(result_code)) {
                                if ("SYSTEMERROR".equalsIgnoreCase(err_code) || "ORDERPAID".equalsIgnoreCase(err_code) || "ORDER_ACCEPTED".equalsIgnoreCase(err_code)) {
                                    retAts.transState = "2";
                                } else {
                                    retAts.transState = "1";
                                }
                                retAts.respInfo = tmpBkReader.getFirstText("/xml/err_code_des");
                                retAts.errCode = err_code;
                            }
                        } else {
                            retAts.respCode = "-1";
                            retAts.respInfo = return_msg;
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = tmpSbMsg.toString();
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = tmpStrRet[1];
                }
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = "未找到账号:[" + p_req.ownAct + "]商户配置信息,请检查'config/portfiles/" + p_req.reqHeader.bankCode + "/config.xml'中该账号相关商户配置节点是否配置正确!";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }

        return retAts;
    }

    /**
     * 参考文档：https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_10&index=14
     *
     * 业务场景：该接口仅提供微信代扣订单的查询，商户可以通过该接口主动查询微信代扣订单状态，完成下一步的业务逻辑。
     * 需要调用查询接口的情况：
     * 1、当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知；
     * 2、调用支付接口后，返回系统错误或未知交易状态情况；
     *
     * 接口链接
     * https://api.mch.weixin.qq.com/pay/paporderquery
     *
     * 是否需要证书
     * 不需要
     * @param p_req
     * @return
     */
    @Override
    public RetAtsQueryEntrustRec queryEntrustRec(ReqQueryEntrustRec p_req) {
        RetAtsQueryEntrustRec retAts = new RetAtsQueryEntrustRec(p_req);

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_req.ownAct,"unifiedorder");
            if (actItem != null) {
                ArrayList<String> arrayParams = new ArrayList<String>();

                StringBuilder sbXml = new StringBuilder();
                sbXml.append("<xml>\r\n");

                sbXml.append("  <appid>" + actItem.appId + "</appid>\r\n");
                arrayParams.add("appid=" + actItem.appId);

                sbXml.append("  <mch_id>" + actItem.merchantId + "</mch_id>\r\n");
                arrayParams.add("mch_id=" + actItem.merchantId);

                sbXml.append("  <out_trade_no>" + p_req.rdSeq + "</out_trade_no>\r\n");
                arrayParams.add("out_trade_no=" + p_req.rdSeq);

                String nonce_str = get_nonce_str();
                sbXml.append("  <nonce_str>" + nonce_str + "</nonce_str>\r\n");
                arrayParams.add("nonce_str=" + nonce_str);

                String[] signParams = new String[arrayParams.size()];
                arrayParams.toArray(signParams);
                String sign = signMessage(signParams, actItem.saltKey);
                sbXml.append("  <sign>" + sign + "</sign>\r\n");
                sbXml.append("</xml>");

                String[] tmpStrRet = sendToBank(sbXml.toString(), "paporderquery");

                if (tmpStrRet[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1],	tmpSbMsg);
                    if (tmpBkReader != null) {
                        String return_code = tmpBkReader.getFirstText("/xml/return_code");
                        String return_msg = tmpBkReader.getFirstText("/xml/return_msg");
                        if (return_code != null && return_code.equals("SUCCESS")) {
                            String result_code = tmpBkReader.getFirstText("/xml/result_code");
                            String err_code = tmpBkReader.getFirstText("/xml/err_code");
                            String trade_state = tmpBkReader.getFirstText("/xml/trade_state");
                            retAts.respCode = "0";
                            retAts.transState = StringHelper.joinNotEmpty("+", result_code, err_code, trade_state);
                            retAts.payInfoCode = StringHelper.joinNotEmpty("+",	err_code, trade_state);
                            if (result_code != null	&& result_code.equals("SUCCESS")) {
                                retAts.respInfo = return_msg;
                                retAts.payInfoCode = tmpBkReader.getFirstText("/xml/trade_state_desc");
                                retAts.openId = tmpBkReader.getFirstText("/xml/openid");
                                retAts.outTradeNo = tmpBkReader.getFirstText("/xml/transaction_id");
                                retAts.oppBank = tmpBkReader.getFirstText("/xml/bank_type");
                            } else {
                                String err_code_des = tmpBkReader.getFirstText("/xml/err_code_des");
                                retAts.respCode = "-1";
                                retAts.respInfo = err_code_des;
                                if (StringHelper.hasAnyChar(tmpBkReader.getFirstText("/xml/err_code_des"))) {
                                    retAts.respInfo = tmpBkReader.getFirstText("/xml/err_code_des");
                                }
                                if (retAts.respInfo.contains("order not exist")) {
                                    retAts.respCode = "0";
                                    retAts.payInfoCode = retAts.respInfo;
                                }
                            }
                        } else {
                            retAts.respCode = "-1";
                            retAts.respInfo = return_msg;
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = tmpSbMsg.toString();
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = tmpStrRet[1];
                }
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = "未找到账号:[" + p_req.ownAct + "]商户配置信息,请检查'config/portfiles/" + p_req.reqHeader.bankCode + "/config.xml'中该账号相关商户配置节点是否配置正确!";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }

        return retAts;
    }
}
